#include <iostream>
#include "Xps/Protocol/TCP/ClientSession.h"

namespace Xps
{
    namespace TCP
    {
        ClientSession::ClientSession( asio::io_service &_io_service, concurrent_in_queue &_incomming_queue, HANDLE _RecieveEvent, const IObjectFactory *_ObjectFactory)
            :socket(_io_service), incomming_queue(_incomming_queue), is_running(false), recieve_event(_RecieveEvent), object_factory(_ObjectFactory)
        {

        }

        void ClientSession::Start()
        {
            if(!is_running)
            {
                is_running = true;
                m_thread = boost::thread(&ClientSession::Run,this);
            }
        }

        void ClientSession::Stop()
        {
            if(is_running)
            {
                is_running = false;
                TerminateThread(m_thread.native_handle(),0);
                socket.shutdown(tcp::socket::shutdown_both);
                socket.close();
            }
        }

        void ClientSession::Send( IPacket::Ptr _Packet )
        {
            static byte byte_buffer[MAX_PACKET_SIZE];
            try
            {
                memset(byte_buffer,0,MAX_PACKET_SIZE);
                long length = object_factory->ToBytes(_Packet->getPayload(),byte_buffer,MAX_PACKET_SIZE);
                socket.send(asio::buffer(byte_buffer,length));
            }
            catch(...)
            {
                Stop();
            }
        }

        void ClientSession::Run()
        {
            static byte byte_buffer[MAX_PACKET_SIZE];
            while(is_running)
            {
                memset(byte_buffer,0,MAX_PACKET_SIZE);

                try
                {
                    long length = socket.receive(asio::buffer(byte_buffer,MAX_PACKET_SIZE));
                    IObject::Ptr object = object_factory->FromBytes(byte_buffer, length);
                    incomming_queue.push(object);
                    SetEvent(recieve_event);
                }           
                catch(...)
                {
                    Stop();
                }
            }
        }

        tcp::socket & ClientSession::getSocket()
        {
            return socket;
        }

        bool ClientSession::IsRunning() const
        {
            return is_running;
        }

        ClientSession::~ClientSession( void )
        {
            Stop();
        }
    };
};